#include "ma_uart_rxhandle.h"
#include "FreeRTOS.h"
#include "queue.h"
#include "stm32f4xx_ll_dma.h"
#include "stm32f4xx_ll_usart.h"
#include "task.h"
#include <stdlib.h>

TaskHandle_t UART_RxHandleTask_Handle = NULL;

extern QueueHandle_t pRxBuffQueue_Handle;

#define UART_IDLE_NOTIFCATION (1 << 0)     // 串口空闲事件标志
#define CLEAR_ALL_NOTIFCATION (0xffffffff) // 清除所有标志

// Rx Buffer实例
static UART_RxBuff_Type UART_RxBuff[RX_BUFFER_NUM];

static void UART_DMA_Config(uint32_t MemoryAddress, uint32_t NbData)
{
    LL_DMA_SetMemoryAddress(DMA2, LL_DMA_STREAM_2, MemoryAddress);
    LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_2, NbData);
    LL_DMA_ClearFlag_HT2(DMA2);
    LL_DMA_ClearFlag_TC2(DMA2);
    LL_DMA_EnableStream(DMA2, LL_DMA_STREAM_2);
}

static uint8_t Cal_CRC8(uint8_t *di, uint32_t len)
{
    uint8_t crc_poly = 0x07; // X^8+X^2+X^1+1 total 8 effective bits without X^8.
    uint8_t data_t = 0;

    while (len--)
    {
        data_t ^= *di++;
        for (int8_t i = 8; i > 0; --i)
        {
            if (data_t & 0x80)
                data_t = (data_t << 1) ^ crc_poly;
            else
                data_t = (data_t << 1);
        }
    }
    return (data_t);
}

void USART1_IRQHandler()
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    if (LL_USART_IsEnabledIT_IDLE(USART1) && LL_USART_IsActiveFlag_IDLE(USART1))
    {
        LL_USART_ClearFlag_IDLE(USART1);

        // 重新配置DMA需要先Disable DMA
        LL_DMA_DisableStream(DMA2, LL_DMA_STREAM_2);

        // 发送串口空闲任务通知，唤醒UART_RxHandleTask任务
        xTaskNotifyFromISR(UART_RxHandleTask_Handle, UART_IDLE_NOTIFCATION,
                           eSetValueWithoutOverwrite, &xHigherPriorityTaskWoken);

        // 如果需要任务切换，则切换
        if (xHigherPriorityTaskWoken != pdFALSE)
            portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}

void UART_RxHandleTask(void)
{
    static uint8_t cur_buff_index = 0; // 当前buffer下标
    uint32_t ulNotifyValue;            // 任务通知值
    UART_RxBuff_Type *pbuffer;         // 指针，指向原始数据buffer

    LL_USART_EnableIT_IDLE(USART1);
    LL_USART_EnableDMAReq_RX(USART1);
    LL_DMA_SetPeriphAddress(DMA2, LL_DMA_STREAM_2, LL_USART_DMA_GetRegAddr(USART1));
    UART_DMA_Config((uint32_t)(UART_RxBuff[0].rx_data), RX_BUFFER_SIZE);

    while (1)
    {
        /* 等待串口空闲中断的任务通知 */
        xTaskNotifyWait(CLEAR_ALL_NOTIFCATION, CLEAR_ALL_NOTIFCATION, &ulNotifyValue, portMAX_DELAY);

        /* 计算实际接收长度 */
        UART_RxBuff[cur_buff_index].rx_len = RX_BUFFER_SIZE - LL_DMA_GetDataLength(DMA2, LL_DMA_STREAM_2);
        pbuffer = &UART_RxBuff[cur_buff_index];
        log_i("Buffer%d received %d bytes!", cur_buff_index, UART_RxBuff[cur_buff_index].rx_len);

        /* 手动切换到下一个缓冲区，准备下次接收 */
        cur_buff_index++;
        if (cur_buff_index >= RX_BUFFER_NUM)
            cur_buff_index = 0;
        UART_DMA_Config((uint32_t)(UART_RxBuff[cur_buff_index].rx_data), RX_BUFFER_SIZE);

        /* 解包数据 */
        UART_RxBuff_Type *unpack_data = (UART_RxBuff_Type *)malloc(sizeof(UART_RxBuff_Type));
        unpack_data->rx_len = 0;

        uint8_t rx_handle_state = 0;                   // 数据处理状态机的状态
        for (uint32_t i = 0; i < pbuffer->rx_len; i++) // 遍历数据，匹配帧头帧尾
        {
            switch (rx_handle_state)
            {
            case 0:
                if (pbuffer->rx_data[i] == 0xFF) // 帧头
                {
                    unpack_data->rx_data[0] = pbuffer->rx_data[i];
                    unpack_data->rx_len = 1;
                    rx_handle_state = 1;
                }
                break;
            case 1:
                if (pbuffer->rx_data[i] == 0xFE) // 帧尾
                {
                    unpack_data->rx_data[unpack_data->rx_len++] = pbuffer->rx_data[i];
                    goto end_statemachine; // 找到帧尾，处理结束
                }
                else if (pbuffer->rx_data[i] != NULL) // 数据
                {
                    unpack_data->rx_data[unpack_data->rx_len++] = pbuffer->rx_data[i];
                }
                break;
            default:
                break;
            }
        }

    end_statemachine:
        if (unpack_data->rx_len == 0)
        {
            log_i("Don't checked the start of frame!"); // 未检测到帧头
            free(unpack_data);
        }
        else if (unpack_data->rx_data[unpack_data->rx_len - 1] != 0xFE)
        {
            log_i("Don't checked the end of frame!"); // 未检测到帧尾
            free(unpack_data);
        }
        else
        {
            /* 匹配校验位，使用CRC8校验 */
            uint8_t crc8_result = Cal_CRC8((uint8_t *)&(unpack_data->rx_data[1]), unpack_data->rx_len - 3);
            if (unpack_data->rx_data[unpack_data->rx_len - 2] == crc8_result)
            {
                // 校验通过，发送消息队列，打印任务处理完会free动态分配的buffer
                xQueueSend(pRxBuffQueue_Handle, &unpack_data, 3);
            }
            else
            {
                log_i("CRC8 parity failed"); // 校验失败
                free(unpack_data);
            }
        }
    }
}
